package com.cgah

import com.cgah.exceptions.ListingNotFoundException
import javax.jws.WebMethod
import javax.jws.WebResult
import javax.jws.WebParam
import grails.converters.JSON

@Grab('net.sf.json-lib:json-lib:2.4:jdk15')
import net.sf.json.groovy.JsonSlurper
import java.text.SimpleDateFormat

class ListingService {//implements com.cgah.api.ListingService {
    static expose=['cxfjax']
    static transactional = true

    // W-3: Expose the three Grails service methods created for S-1, S-2, and S-3 via SOAP/WSD
/*
    @WebResult(name="Listing")
    @WebMethod(operationName="create")
*/
    def create(def params) {
        def listingInstance = new Listing()
        listingInstance.properties = params
        return [listingInstance: listingInstance]
    }

    // W-3: Expose the three Grails service methods created for S-1, S-2, and S-3 via SOAP/WSD
    @WebResult(name="Listing")
    @WebMethod(operationName="save")
    Listing save(@WebParam(name="listing") Listing listing, String userName, String password) {
        def user = UserUtil.getUser(userName, password);
        if (user) {
            listing.seller = user;
            if (!listing.createdDateTime) {
                listing.createdDateTime = new Date();
            }
            return listing.save(flush:true)
        } else {
            log.error("failed to get user for seller and password, (" + userName + ", " + password + ")")
            throw new ListingNotFoundException("listing cannot be saved.");
        }
    }


    def save(def params,  def sellerId) {
        params.createdDateTime = new Date();
        params.'seller.id' = sellerId
        // is this needed?
//        params.seller = seller
        def listingInstance = new Listing(params)
        listingInstance.save(flush: true)
        return listingInstance;
    }


    def list(def params, def userName, def password) {
        def user = UserUtil.getUser(userName, password);
        if (user) {
            return list(params);
        } else {
            log.error("failed to get user for username and password, (" + username + ", " + password + ")")
            return new ArrayList();
        }
    }

    def list(def params) {
        return (Listing.findAll("from Listing as l where l.endDateTime > sysdate order by " + params.sort + " " + params.order,  // can you say fail?
                [max: params.max?.toInteger(), offset: params.offset?.toInteger()]));
    }



    def listAllForUser(def params, def userName, def password) {
        // I would use AOP for this, but at this point IDC
        def user = UserUtil.getUser(userName, password);
        if (user) {
            return listAllForUser(params, user.userId);
        } else {
            log.error("failed to get user for username and password, (" + userName + ", " + password + ")")
            return new ArrayList();
        }
    }

    def listAllForUser(def params, def userId) {
        return Listing.findAll("from Listing as l where l.endDateTime > sysdate and seller.id = " + userId + " order by " + params.sort + " " + params.order);
    }


    def getListingById(def id, def userName, def password) throws ListingNotFoundException {
        def user = UserUtil.getUser(userName, password);
        if (user) {
            return getListingById(params);
        } else {
            log.error("failed to get user for username and password, (" + userName + ", " + password + ")")
            //return new Listing();
            throw new ListingNotFoundException("Cannot get listing with id " + id);
        }
    }

    def getListingById(def id) throws ListingNotFoundException {
        def listing = Listing.get(id)
        if (null == listing) {
            throw new ListingNotFoundException("Listing with id: " + id + " does not exists.");
        }
        return listing;
    }

    def updateListing(def params, def userName, def password) throws ListingNotFoundException {
        def user = UserUtil.getUser(userName, password);
        if (user) {
            return updateListing(params);
        } else {
            log.error("failed to get user for username and password, (" + username + ", " + password + ")")
            throw new ListingNotFoundException("Cannot update listing with id " + params.id);
        }
    }


    def updateListing(def params) throws ListingNotFoundException {
        def listingInstance = this.getListingById(params.id)
        if (params.version && listingInstance.version > params.version.toLong()) {
            listingInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
                    [message(code: 'listing.label', default: 'Listing')] as Object[],
                    "Another user has updated this Listing while you were editing")
        } else {
            listingInstance.properties = params
            if (!listingInstance.hasErrors()) {
                listingInstance = listingInstance.save(flush: true)
            }
        }
        return listingInstance;
    }


    def lastBids (def id, def max, def userName, def password) {
         def user = UserUtil.getUser(userName, password);
        if (user) {
            return lastBids(id, max);
        } else {
            log.error("failed to get user for username and password, (" + username + ", " + password + ")")
            return new ArrayList();
        }
    }

    def lastBids (def id, def max) {
        //return Bid.lastTen(this.getListingById(id)).list(max: 10, fetch:[customer:"eager"]);
        return Bid.lastNBids(this.getListingById(id)).list(max: max, fetch: [customer: "eager"]); //Bid.list(max: 10, fetch:[customer:"eager"]);//;
    }

    def getExpiredListings()
    {
        // Get the expried listings.
        return Listing.findAll("from Listing as l where l.endDateTime < sysdate and processed=false");
    }

    // C-5: Provide a JMS Queue listener that will create a new listing based on XML or JSON specified in an incoming message. (integration test).
    // consume the message on the Q
    // grails is so fails, I fuking have no idea how to convert a JSON string to an object!
    // this shit took me all night! FAIL
    def onNewListing(def jsonString) {
        try {
            println "onNewListing q message: " + jsonString
            // fuk this pos grails = fails json conversion, what a waste of time!
            def fail = new JsonSlurper().parseText( jsonString )
            Listing listing = new JsonSlurper().parseText( jsonString )
            listing.createdDateTime = new Date();

            if (fail.endDateTime && !fail.endDateTime?.toString().equalsIgnoreCase("null")) {
                listing.endDateTime = new Date(javax.xml.bind.DatatypeConverter.parseDateTime(fail.endDateTime).timeInMillis) //fail.endDateTime); // yyyy-dd-hh24
            }

            listing.seller = Customer.get( fail.seller.id )
            listing.processed = false
            listing.bids = new ArrayList();
            listing.winner = null;

            if(!listing.validate()) {
                listing.errors.allErrors.each {
                    println it
                }
            }

            listing = listing.save(flush:true) // = this.save(listing);

            println ("l is " + listing )

        } catch (Exception e) {
            e.printStackTrace()
        } finally {
            return null; // clear q! message processed
        }
    }

}
